﻿using FtpTestTool.model;
using System;
using System.IO;
using System.Net;

namespace FtpTestTool
{

    /// <summary>
    /// Ftp资源访问助手
    /// </summary>
    public class FtpResourceHelper
    {
        private static FtpResourceHelper _instance;

        private FtpResourceHelper()
        {
        }

        /// <summary>
        /// Ftp资源访问助手
        /// </summary>
        public static FtpResourceHelper Instance
        {
            get { return _instance ?? (_instance = new FtpResourceHelper()); }
        }

        #region FTP资源WEB访问

        /// <summary>
        /// FTP资源访问根路径
        /// </summary>
        public string SourceRootPath
        {
            get { return string.Format("{0}://{1}:{2}{3}", WebSiteProtocol, WebSiteIp, WebSitePort, WebSitePath); }
        }

        /// <summary>
        /// Ftp资源访问协议
        /// </summary>
        public string WebSiteProtocol { get; set; }

        /// <summary>
        /// Ftp资源访问IP
        /// </summary>
        public string WebSiteIp { get; set; }

        /// <summary>
        /// Ftp资源访问端口
        /// </summary>
        public string WebSitePort { get; set; }

        /// <summary>
        /// Ftp资源访问虚拟站路径
        /// </summary>
        public string WebSitePath { get; set; }

        #endregion

        /// <summary>
        /// FTP操作对象
        /// </summary>
        public FtpClient getFtpClient(FtpPortInfo ftp, bool usePassive)
        {
            return new FtpClient(ftp, usePassive);
        }
    }

    /// <summary>
    /// 文件上传实现
    /// </summary>
    public class FtpClient : IDisposable
    {
        public FtpClient(FtpPortInfo ftp, bool usePassive)
        {
            WebUpProtocol = "ftp";
            WebUpIp = ftp.Ip;
            WebUpUid = ftp.Uid;
            WebUpPass = ftp.Pwd;
            WebUpPort = ftp.Port;
            if (WebUpPort == 0)
                WebUpPort = 21;
            this.UsePassive = usePassive;
        }

        public void Dispose()
        {

        }

        /// <summary>
        /// FTP根路径
        /// </summary>
        /// <returns></returns>
        //public string FtpRootPath() => $"{this.WebUpProtocol}://{this.WebUpIp}:{this.WebUpPort}/";
        public string FtpRootPath()
        {
            return string.Format("{0}://{1}:{2}/", WebUpProtocol, WebUpIp, WebUpPort);
        }

        /// <summary>
        /// FTP资源上传协议
        /// </summary>
        public string WebUpProtocol { get; private set; }
        /// <summary>
        /// Ftp资源上传IP
        /// </summary>
        public string WebUpIp { get; private set; }
        /// <summary>
        /// Ftp资源上传端口
        /// </summary>
        public int WebUpPort { get; private set; }
        /// <summary>
        /// Ftp资源上传账号
        /// </summary>
        public string WebUpUid { get; private set; }
        /// <summary>
        /// Ftp资源上传密码
        /// </summary>
        public string WebUpPass { get; private set; }

        /// <summary>
        /// 是否被动模式
        /// </summary>
        public bool UsePassive { get; private set; }

        /// <summary>
        /// 上传
        /// </summary>
        /// <param name="filePhysicsPath">文件的物理路径</param>
        /// <param name="ftpDirPath">将要上传到ftp服务器的文件夹路径</param>
        /// <returns>文件信息</returns>
        public SingleData<string> Upload(string filePhysicsPath, string ftpDirPath,bool delOrginFile=false)
        {
            SingleData<string> objRet = new SingleData<string>();
            FileInfo fileinfo = new FileInfo(filePhysicsPath);

            //根据uri创建FtpWebRequest对象
            FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(new Uri(FtpRootPath() + ftpDirPath + "/" + fileinfo.Name));

            //ftp用户名和密码
            ftp.Credentials = new NetworkCredential(WebUpUid, WebUpPass);

            //在一个命令完成之后是否关闭连接
            ftp.KeepAlive = false;

            //指定执行什么命令
            ftp.Method = WebRequestMethods.Ftp.UploadFile;

            //为true时 传输的二进制
            ftp.UseBinary = true;
            ftp.Proxy = null;

            //
            ftp.UsePassive = this.UsePassive;

            //指定长度
            ftp.ContentLength = fileinfo.Length;

            //缓冲大小设置 20kb
            int bufflength = 1024 * 10;

            byte[] buff = new byte[bufflength];
            int contentLen;

            //打开一个文件流
            FileStream fs = fileinfo.OpenRead();
            Stream strm = null;

            try
            {
                //把上传的文件写入流
                strm = ftp.GetRequestStream();

                //每次读文件流的2kb
                contentLen = fs.Read(buff, 0, bufflength);
                while (contentLen != 0)
                {
                    strm.Write(buff, 0, contentLen);
                    contentLen = fs.Read(buff, 0, contentLen);
                    strm.Flush();
                }
                strm.Flush();
                //关闭两个流
                strm.Close();
                strm = null;
                objRet.Message = "ok";
                objRet.State = RequestResultType.Ok;
                if (delOrginFile)
                {
                    fileinfo = null;
                    File.Delete(filePhysicsPath);
                }
            }
            catch (Exception e)
            {
                objRet.Message = e.Message;
                objRet.State = RequestResultType.Fail;
            }
            finally
            {
                if (strm != null)
                {
                    strm.Close();
                    strm = null;
                }
                if (fs != null)
                {
                    fs.Close();
                    fs = null;
                }
                if (ftp != null)
                {
                    ftp = null;
                }
                if (fileinfo != null)
                {
                    fileinfo = null;
                }
            }
            return objRet;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="ftpFilePath">文件路径</param>
        /// <returns>删除结果</returns>
        public SingleData<string> Delete(string ftpFilePath)
        {
            SingleData<string> objRet = new SingleData<string>();

            //ftp响应信息
            FtpWebResponse resFtp = null;
            try
            {
                FtpWebRequest reqFtp = (FtpWebRequest)FtpWebRequest.Create(new Uri(FtpRootPath() + ftpFilePath));
                reqFtp.Credentials = new NetworkCredential(WebUpUid, WebUpPass);
                reqFtp.KeepAlive = false;
                reqFtp.Proxy = null;

                reqFtp.Method = WebRequestMethods.Ftp.DeleteFile;
                resFtp = (FtpWebResponse)reqFtp.GetResponse();
                reqFtp = null;
                objRet.Message = "ok";
                objRet.State = RequestResultType.Ok;
            }
            catch (Exception e)
            {
                objRet.Message = e.Message;
            }
            finally
            {
                if (resFtp != null)
                {
                    resFtp.Close();
                }
            }

            return objRet;
        }


        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="localPath">本地文件地址(没有文件名)</param>
        /// <param name="localFileName">本地文件名</param>
        /// <param name="ftpPath">下载的ftp的路径</param>
        /// <param name="ftpFileName">下载的ftp的文件名</param>
        public SingleData<MemoryStream> Download(string ftpFileName)
        {
            FtpWebRequest ftpWebRequest = null;
            FtpWebResponse ftpWebResponse = null;
            Stream ftpResponseStream = null;
            MemoryStream outputStream = null;

            SingleData<MemoryStream> objRet = new SingleData<MemoryStream>();

            try
            {
                outputStream = new MemoryStream();
                string uri = FtpRootPath() + "/" + ftpFileName;
                ftpWebRequest = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
                ftpWebRequest.Credentials = new NetworkCredential(WebUpUid, WebUpPass);
                ftpWebRequest.UseBinary = true;
                ftpWebRequest.KeepAlive = false;
                ftpWebRequest.Proxy = null;
                ftpWebRequest.UsePassive = this.UsePassive;
                ftpWebRequest.Method = WebRequestMethods.Ftp.DownloadFile;
                ftpWebResponse = (FtpWebResponse)ftpWebRequest.GetResponse();
                ftpResponseStream = ftpWebResponse.GetResponseStream();
                int bufferSize = 2048;
                byte[] buffer = new byte[bufferSize];
                int readCount;
                while ((readCount = ftpResponseStream.Read(buffer, 0, bufferSize)) > 0)
                {
                    outputStream.Write(buffer, 0, readCount);
                }
                ftpResponseStream.Close();
                ftpWebRequest = null;
                ftpResponseStream = null;
                objRet.Data = outputStream;
                objRet.Message = "FTP取流成功";
                objRet.State = RequestResultType.Ok;

            }
            catch (Exception e)
            {
                objRet.Data = null;
                objRet.Message = "FTP取流失败";
                objRet.State = RequestResultType.Fail;
            }
            finally
            {
                if (outputStream != null)
                {
                    outputStream.Close();
                }
                if (ftpResponseStream != null)
                {
                    ftpResponseStream.Close();
                }
                if (ftpWebResponse != null)
                {
                    ftpWebResponse.Close();
                }
                if (ftpWebRequest != null)
                {
                    ftpWebRequest = null;
                }
                if (ftpResponseStream == null)
                {
                    ftpResponseStream = null;
                }
            }
            return objRet;
        }

        /// <summary>
        /// 检测目录是否存在
        /// </summary>
        /// <param name="path">ftp服务器上的相对地址</param>
        /// <returns>检测结果</returns>
        public SingleData<bool> CheckDirectory(string path)
        {
            SingleData<bool> ret = new SingleData<bool>();
            //根据路径创建uri对象
            Uri uri = new Uri(FtpRootPath() + path);
            try
            {
                FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(uri);
                ftp.UseBinary = true;
                ftp.KeepAlive = false;
                ftp.Proxy = null;
                ftp.Credentials = new NetworkCredential(WebUpUid, WebUpPass);
                ftp.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
                WebResponse res = ftp.GetResponse(); //如果访问的文件夹存在  那么此句正常运行，否则报错
                StreamReader reader = new StreamReader(res.GetResponseStream());
                string line = reader.ReadLine();
                while (line != null)
                {
                    line = reader.ReadLine();
                }
                reader.Close();
                res.Close();
                ret.State = RequestResultType.Ok;
                ret.Message = "ok";
                ret.Data = true;
                ftp = null;
            }
            catch (Exception e)
            {
                ret.State = RequestResultType.Ok;
                ret.Message = e.Message;
                ret.Data = false;
            }
            return ret;
        }

        /// <summary>
        /// 创建文件夹
        /// </summary>
        /// <param name="path">路径</param>
        /// <returns>是否创建成功</returns>
        public SingleData<bool> CreateDirectory(string path)
        {
            SingleData<bool> ret = new SingleData<bool>();
            try
            {
                FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(new Uri(FtpRootPath() + path));
                ftp.Credentials = new NetworkCredential(WebUpUid, WebUpPass);
                ftp.KeepAlive = false;
                ftp.UseBinary = true;
                ftp.Proxy = null;
                ftp.Method = WebRequestMethods.Ftp.MakeDirectory;
                FtpWebResponse response = ftp.GetResponse() as FtpWebResponse;
                response.Close();
                ret.State = RequestResultType.Ok;
                ret.Message = "ok";
                ret.Data = true;
                ftp = null;
            }
            catch (Exception e)
            {
                ret.State = RequestResultType.Fail;
                ret.Message = e.Message;
                ret.Data = false;
            }
            return ret;
        }

        /// <summary>
        /// 检查文件夹，如果不存在则创建该文件夹
        /// </summary>
        /// <param name="path"></param>
        /// <returns>检存在或创建成功则返回True ，否则返回False</returns>
        public SingleData<string> CheckAndCreateDirectory(string path)
        {
            SingleData<string> objRet = new SingleData<string>();
            var s1 = CheckDirectory(path);
            if (s1.State != RequestResultType.Ok)
            {
                objRet.State = RequestResultType.Fail;
                objRet.Message = s1.Message;
                return objRet;
            }
            if (!s1.Data)
            {
                var s2 = CreateDirectory(path);
                if (s2.State != RequestResultType.Ok)
                {
                    objRet.State = RequestResultType.Fail;
                    objRet.Message = s1.Message;
                    return objRet;
                }
                //如果不存在文件夹，则新建一个文件夹，如果该文件夹创建失败，向页面抛出错误
                if (!s2.Data)
                {
                    objRet.Message = "ftp远程创建文件夹失败，请重试！";
                    objRet.Message = s2.Message;
                    objRet.State = RequestResultType.Fail;
                    return objRet;
                }
            }
            objRet.Message = "ok";
            objRet.State = RequestResultType.Ok;
            return objRet;
        }


    }
}
